package com.desaysv.wandroid.utils;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.desaysv.wandroid.R;
import com.desaysv.wandroid.databinding.LayoutWindowBinding;
import com.desaysv.wandroid.projection.ProjectionActivity;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author linzi
 * @date 2022-12-6
 */
public class ProjectionService extends Service implements SurfaceHolder.Callback {
    private static final String TAG = "[ProjectionService]";
    private MediaProjectionManager projectionManager = null;
    private MediaProjection mMediaProject;
    private static SurfaceView mSurfaceView;
    private SurfaceHolder surfaceHolder;
    private int width;
    private int height;
    private int dpi = 320;
    private VirtualDisplay virtualDisplay;
    private int status = 0;
    private final ExecutorService mPool = Executors.newFixedThreadPool(1);
    private static ProjectionService instence;

    public static ProjectionService getInstance() {
        return instence;
    }

    public void setmMediaProject(MediaProjection mMediaProject) {
        this.mMediaProject = mMediaProject;
        createVirtualDislplay();
    }

    public static SurfaceView getmSurfaceView() {
        return mSurfaceView;
    }

    public MediaProjectionManager getProjectionManager() {
        return projectionManager;
    }

    public static SurfaceView start(Context context, SurfaceView surfaceView) {
        Log.i(TAG, "start: ");
        if (surfaceView == null) {
            mSurfaceView = new SurfaceView(context);
        } else {
            ProjectionService.mSurfaceView = surfaceView;
        }
        Intent intent = new Intent(context, ProjectionService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent);
        } else {
            context.startService(intent);
        }
        return mSurfaceView;
    }

    public void stopService() {
        stopSelf();
    }

    private void initSurface() {
        Log.e(TAG, "initSurface: ");
        mSurfaceView.getHolder().addCallback(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void notification() {
        Log.i(TAG, "notification: " + Build.VERSION.SDK_INT);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //Call Start foreground with notification
            Intent notificationIntent = new Intent(this, ProjectionService.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, this.getPackageName())
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
                    .setSmallIcon(R.drawable.ic_launcher_foreground)
                    .setContentTitle("Starting Service")
                    .setContentText("Starting monitoring service")
                    .setTicker("xxx")
                    .setContentIntent(pendingIntent);
            Notification notification = notificationBuilder.build();
            NotificationChannel channel = new NotificationChannel(this.getPackageName(), this.getPackageName(), NotificationManager.IMPORTANCE_DEFAULT);
            channel.setDescription("123");
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
            //notificationManager.notify(NOTIFICATION_ID, notification);
            startForeground(1, notification); //必须使用此方法显示通知，不能使用notificationManager.notify，否则还是会报上面的错误
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: ");
        instence = this;
        initWindow();
    }

    /************悬浮窗相关*************/
    public static boolean requestPermission(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return Settings.canDrawOverlays(context);
        }
        return false;
    }

    private WindowManager windowManager;
    private LayoutWindowBinding root;
    private WindowManager.LayoutParams mLayoutParams;

    public void initWindow() {
        if (windowManager == null) {
            windowManager = (WindowManager) getBaseContext().getSystemService(Context.WINDOW_SERVICE);
            root = LayoutWindowBinding.inflate(LayoutInflater.from(getBaseContext()));
        }
        addWindow();
    }

    /**
     * 添加显示视图
     */
    public void addWindow() {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M || !ProjectionService.requestPermission(getBaseContext())) {
            return;
        }
        if (mLayoutParams == null) {
            mLayoutParams = new WindowManager.LayoutParams();
            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP; //窗口位置
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            } else {
                mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
            }
            mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            mLayoutParams.x = 0;
            mLayoutParams.y = 0;
            DisplayMetrics displayMetrics = getBaseContext().getResources().getDisplayMetrics();
            mLayoutParams.width = displayMetrics.widthPixels / 3;
            mLayoutParams.height = displayMetrics.heightPixels / 3;
        }
        windowManager.addView(root.getRoot(), mLayoutParams);
        setListener();
    }

    /**
     * 刷新 view 位置
     */
    private void updateViewLayout() {
        if (null != root && null != mLayoutParams && windowManager != null) {
            try {
                windowManager.updateViewLayout(root.getRoot(), mLayoutParams);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void remove() {
        if (null != root && null != mLayoutParams && windowManager != null) {
            try {
                windowManager.removeView(root.getRoot());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置 悬浮窗 view 滑动事件
     */
    private boolean isMove = false;

    @SuppressLint("ClickableViewAccessibility")
    private void setListener() {
        if (root != null) {
            root.getRoot().setOnTouchListener(new View.OnTouchListener() {
                /**
                 * 起始点X
                 */
                int startX,
                /**
                 * 起始点Y
                 */
                startY;

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    boolean result = false;
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            startX = (int) event.getX();
                            startY = (int) event.getY();
                            break;
                        case MotionEvent.ACTION_MOVE:
                            isMove = true;
                            //当移动距离大于2时候，刷新界面。
                            if (Math.abs(startX - event.getX()) > 2 || Math.abs(startY - event.getY()) > 2) {
                                mLayoutParams.x = (int) (event.getRawX() - startX);
                                mLayoutParams.y = (int) (event.getRawY() - startY);
                                updateViewLayout();   //更新mView 的位置
                            }
                            result = true;
                            break;
                        case MotionEvent.ACTION_UP:
                            isMove = false;
                            break;
                        default:
                    }
                    return result;
                }
            });
        }
        mSurfaceView = root.surface;
        resetBt();
        init();
        initSurface();
    }

    /************悬浮窗相关*************/


    public void startRequest() {
        status = 2;
        Intent intent = new Intent(getBaseContext(), ProjectionActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        getBaseContext().startActivity(intent);
        resetBt();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        notification();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stop();
        instence = null;
    }

    private void init() {
        if (projectionManager != null) {
            return;
        }
        projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
    }

    private void createVirtualDislplay() {
        virtualDisplay = mMediaProject.createVirtualDisplay(
                "screen",
                width,
                height,
                dpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                surfaceHolder.getSurface(),
                null, null
        );
        resetBt();
    }

    private void stop() {
        virtualDisplay.release();
        virtualDisplay = null;
        mMediaProject.stop();
        mSurfaceView = null;
        status = 1;
        resetBt();
    }

    private void resetBt() {
        switch (status) {
            case 0://准备
                root.tvTips.setText("准备中");
                break;
            case 1://可以开始
                root.tvTips.setText("开始");
                root.tvTips.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        startRequest();
                    }
                });
                break;
            case 2://录制中
                root.tvTips.setText("录制中");
                root.tvTips.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        status = 3;
                        resetBt();
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                stop();
                            }
                        }, 500);

                    }
                });
                break;
            case 3://停止中
                root.tvTips.setText("停止中");
                break;
            default:
        }
        root.tvClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                remove();
                stopService();
            }
        });
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        Log.e(TAG, "surfaceCreated: ");
        surfaceHolder = holder;
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        Log.e(TAG, "surfaceChanged: ");
        this.width = width;
        this.height = height;
        if (virtualDisplay == null) {
            Log.e(TAG, "surfaceChanged2: ");
            status = 1;
            resetBt();
            return;
        }
        createVirtualDislplay();
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        Log.e(TAG, "surfaceDestroyed: ");
        mSurfaceView.getHolder().removeCallback(this);
        surfaceHolder = null;
    }


}
